//
//  main.m
//  MultiperThread
//
//  Created by FelixYin on 2020/4/4.
//  Copyright © 2020 FelixYin. All rights reserved.
//

#import <Foundation/Foundation.h>

/*
 
 概念容易混淆：
 1.dispatch_async,dispatch_sync 决定是否需要开启新线程
 2.队列类型，决定了执行任务执行任务的方式 （是以串行，还是并行方式）
 队列类型有：
 1.串行队列
 2.并行队列
 3.主队列（其实是串行队列）
 
 
 死锁情况总结：
 1.使用sync函数往当前串行队列中添加任务，会卡住当前的串行队列，从而造成死锁
 
 
 
 */
int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        NSLog(@"Hello, World!");
        
//        test1(); //基本使用
        
//        int result = test2(); //死锁
        
        int result = test3();
        
        NSLog(@"=== %@",@(result));

        
    }
    return 0;
}



//GCD 正常情况下使用
int test1(){
    
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    //开启新的任务
    dispatch_async(queue, ^{
        NSLog(@"异步执行 Thread == %@",[NSThread currentThread]);
        for (int i = 0; i < 5; i++) {
            NSLog(@"Thread 😝😝😝😝=== %@",[NSThread currentThread]);
        }
    });
    
    //同步的话就是在当前线程执行任务
    dispatch_sync(queue, ^{
        NSLog(@"同步执行 Thread == %@",[NSThread currentThread]);
        for (int i = 0; i < 5; i++) {
            NSLog(@"Thread 🐶🐶🐶🐶=== %@",[NSThread currentThread]);
        }
    });
    
    return 1;
}

//GCD造成的死锁的情况1
int test2(){
    /*
     死锁原因：
     1.队列特点，排队：First in First out 先进先出
     2.dispatch_sync 需要立马在当前线程执行任务，执行完毕后才能继续往下执行
     
     主队列会执行test2这个一个大任务，又有sync需要立马执行任务，
     */
    dispatch_queue_t queue = dispatch_get_main_queue();
//    dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0);
//    dispatch_queue_t queue3 = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
    
    /*
     解决死锁方法：
     第一种：
     1.将sync改成async
     
     第二种：
     1.将任务添加到新的队列中 （串行或者并行队列都可以  只要不是当前队列就可以）
     
     */
    NSLog(@"任务1");
    dispatch_sync(queue, ^{
       NSLog(@"任务2");
    });
    NSLog(@"任务3");
    
    
    //如果将sync改成async的话就不会死锁， 输出记录是 任务1 === 任务3 === 任务2
    
    return 2;
}


//GCD造成的死锁的情况2
int test3(){
    
    /*
     死锁原因：
     1.当前队列为串行队列
     2.在同一个队列中同步执行任务
     
     */
    
    //创建一个串行队列
    dispatch_queue_t queue = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
//    dispatch_queue_t queue2 = dispatch_get_global_queue(0, 0); //并行队列
//    dispatch_queue_t queue2 = dispatch_queue_create(0, DISPATCH_QUEUE_CONCURRENT); //并行队列
//    dispatch_queue_t queue3 = dispatch_queue_create(0, DISPATCH_QUEUE_SERIAL);
    
    /*
     解决死锁的办法：
     
     第一种：
     1.内部任务2 sync改成async
     
     第二种：
     1.内部任务2 放在一个新的队列中，不在当前队列就可以 （创建一个串行队列或者并行队列）
     
     第三种：
     1.直接将queue队列改成使用 并行队列，就不存在等待问题 （并行任务可以同时执行）
     
     */
    
    NSLog(@"任务1");
    //异步串行执行任务
    dispatch_async(queue, ^{
        dispatch_sync(queue, ^{
           NSLog(@"任务2");
        });
        NSLog(@"任务3");
    });
    NSLog(@"任务4");
    
    return 3;
}
